/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.raysdata.rdc.dataasset.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.raysdata.rdc.dataasset.entity.DataShareToken;
import com.raysdata.rdc.dataasset.utils.JwtUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import javax.validation.Valid;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.raysdata.rdc.dataasset.entity.DataShare;
import com.raysdata.rdc.dataasset.vo.DataShareVO;
import com.raysdata.rdc.dataasset.service.IDataShareService;
import org.springblade.core.boot.ctrl.BladeController;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.*;

/**
 *  控制器
 *
 * @author BladeX
 * @since 2021-05-02
 */
@RestController
//@AllArgsConstructor
@RequestMapping("/datashare")
@Api(value = "", tags = "数据共享接口")
public class DataShareController extends BladeController {
	private static Logger logger = LoggerFactory.getLogger(DataShareController.class);

	@Autowired
	private IDataShareService dataShareService;
	@Autowired
	private RestTemplate restTemplate;

	@Value("${dolphinscheduler.host}")
	private String host;
	@Value("${dolphinscheduler.api.queryTableData}")
	private String api_prefix;
	//@Value("${dolphinscheduler.token}")
	//private String dolphinschedulerToken;


	/**
	 * 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "接口详情", notes = "传入dataShare")
	public R<DataShare> detail(DataShare dataShare) {
		DataShare detail = dataShareService.getOne(Condition.getQueryWrapper(dataShare));
		return R.data(detail);
	}

	/**
	 * 分页 
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "接口列表", notes = "传入dataShare")
	public R<IPage<DataShare>> list(DataShare dataShare, Query query) {
		IPage<DataShare> pages = dataShareService.page(Condition.getPage(query), Condition.getQueryWrapper(dataShare));
		return R.data(pages);
	}

	/**
	 * 自定义分页 
	 */
	@GetMapping("/page")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "接口分页", notes = "传入dataShare")
	public R<IPage<DataShareVO>> page(DataShareVO dataShare, Query query) {
		IPage<DataShareVO> pages = dataShareService.selectDataSharePage(Condition.getPage(query), dataShare);
		return R.data(pages);
	}

	/**
	 * 新增 
	 */
	@PostMapping("/save")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "接口新增", notes = "传入dataShare")
	public R save(@Valid @RequestBody DataShare dataShare) {
		BladeUser currentUser=getUser();
		if(dataShare.getId()==null){

			if(currentUser!=null)dataShare.setCreateUser(getUser().getUserId());
			dataShare.setCreateTime(LocalDateTime.now());
		}
		if(currentUser!=null)dataShare.setUpdateUser(getUser().getUserId());
		dataShare.setUpdateTime(LocalDateTime.now());
		boolean result=dataShareService.save(dataShare);
		return R.status(result);
	}

	/**
	 * 修改 
	 */
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "接口修改", notes = "传入dataShare")
	public R update(@Valid @RequestBody DataShare dataShare) {
		return R.status(dataShareService.updateById(dataShare));
	}

	/**
	 * 新增或修改 
	 */
	@PostMapping("/submit")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "接口新增或修改", notes = "传入dataShare")
	public R submit(@Valid @RequestBody DataShare dataShare) {
		BladeUser currentUser=getUser();
		if(dataShare.getId()==null){

			if(currentUser!=null)dataShare.setCreateUser(getUser().getUserId());
			dataShare.setCreateTime(LocalDateTime.now());
		}
		if(currentUser!=null)dataShare.setUpdateUser(getUser().getUserId());
		dataShare.setUpdateTime(LocalDateTime.now());
		if("[]".equals(dataShare.getInputParams()) || "[]".equals(dataShare.getOutputParams())){
			return R.fail("入参和出参必须设置");
		}
		if(dataShare.getId()==null || StringUtils.isBlank(dataShare.getToken())){
			dataShareService.saveOrUpdate(dataShare);
			//token生效时间结束时间
			Long expireTime=System.currentTimeMillis()+1000L*3600*24*365*10;//10年
			JSONObject data=new JSONObject();
			data.put("id",dataShare.getId());
			String token = JwtUtil.buildToken(data.toJSONString(),expireTime);
			dataShare.setToken(token);
		}
		dataShareService.saveOrUpdate(dataShare);
		return R.data(dataShare);
	}

	
	/**
	 * 删除 
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "接口删除", notes = "传入ids")
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		return R.status(dataShareService.removeByIds(Func.toLongList(ids)));
	}

	/**
	 * 创建token
	 */
	@PostMapping("/createToken")
	@ApiOperationSupport(order = 9)
	@ApiOperation(value = "创建接口token", notes = "传入dataShare")
	public R createToken(@Valid @RequestBody DataShare dataShare) {
		BladeUser currentUser=getUser();
		if(dataShare.getId()==null){

			if(currentUser!=null)dataShare.setCreateUser(getUser().getUserId());
			dataShare.setCreateTime(LocalDateTime.now());
		}
		if(currentUser!=null)dataShare.setUpdateUser(getUser().getUserId());
		dataShare.setUpdateTime(LocalDateTime.now());
		if("[]".equals(dataShare.getInputParams()) || "[]".equals(dataShare.getOutputParams())){
			return R.fail("入参和出参必须设置");
		}
		dataShareService.saveOrUpdate(dataShare);
		//token生效时间结束时间
		Long expireTime=System.currentTimeMillis()+1000L*3600*24*365*10;//10年
		JSONObject data=new JSONObject();
		data.put("id",dataShare.getId());
		String token = JwtUtil.buildToken(data.toJSONString(),expireTime);
		dataShare.setToken(token);
		dataShareService.updateById(dataShare);
		return R.data(dataShare);//
	}

	/**
	 * 数据共享接口
	 */
	@PostMapping("/query/{tableName}")
	@ApiOperationSupport(order = 10)
	@ApiOperation(value = "数据共享接口", notes = "传入数据共享请求参数")
	public R tableData(@Valid @RequestBody JSONObject requestBody,@ApiParam(name = "tableName", value = "tableName", required = true) @PathVariable String tableName) {

		if(StringUtils.isBlank(tableName) || requestBody==null || requestBody.isEmpty()){
			return R.fail("参数错误");
		}
		String token = requestBody.getString("token");
		if(StringUtils.isBlank(token)){
			return R.fail("缺少token");
		}
		Long id=null;
		try {
			String tokenDataString=JwtUtil.volidToken(token);
			JSONObject tokenData=JSONObject.parseObject(tokenDataString) ;
			if(tokenData==null){
				return R.fail("token无效1");
			}
			id=tokenData.getLong("id");
			if(id==null){
				return R.fail("token无效2");
			}
		}catch (JwtUtil.ResultException e){
			if(e.getCode()== JwtUtil.ResultException.INVALID || e.getCode()== JwtUtil.ResultException.NO_DATA){
				return R.fail("token无效3");
			}
			if(e.getCode()== JwtUtil.ResultException.EXPIRED){
				return R.fail("token过期");
			}
		}

		DataShare dataShare=dataShareService.getById(id);
		if(dataShare==null){
			return R.fail("未查询到接口信息");
		}
		//检测请求的信息是否为接口信息一致
		if(!tableName.equals(dataShare.getDataSourceTable())){
			return R.fail("调用不是指定的表");
		}
		//设置数据源
		requestBody.put("dataSourceName",dataShare.getDataSourceDb());
		try{
			JSONArray inputParams=JSONArray.parseArray(dataShare.getInputParams());
			Map<String,Object> settingInputParamMap=new HashMap<>();
			for(int i=0;i<inputParams.size();i++){
				JSONObject item=inputParams.getJSONObject(i);
				settingInputParamMap.put(item.getString("key"),null);
			}
			JSONArray givenInputParams=requestBody.getJSONArray("inputParams");
			JSONArray givenInputParamsFilterEmpty=new JSONArray();
			if(givenInputParams!=null){
				for(int i=0;i<givenInputParams.size();i++){
					JSONObject item=givenInputParams.getJSONObject(i);
					if(!settingInputParamMap.containsKey(item.getString("key"))){
						return R.fail("入参错误，不含参数："+item.getString("key"));
					}
					if(!StringUtils.isBlank(item.getString("value"))){
						givenInputParamsFilterEmpty.add(item);
					}else {
						return R.fail(item.getString("key")+"参数未设置，所有入参都必须设置");
					}
				}
			}
			requestBody.put("inputParams",givenInputParamsFilterEmpty);

		}catch (Exception e){
			logger.error("接口入参设置错误",e);
			return R.fail("接口入参设置错误，请联系管理员");
		}
		//限定出参
		try{
			JSONArray outputParams=JSONArray.parseArray(dataShare.getOutputParams());
			requestBody.put("outputParams",outputParams);
		}catch (Exception e){
			return R.fail("接口出参设置错误，请联系管理员");
		}




		String DATA_INTERFACE_URL=host+api_prefix+tableName;
		//String DATA_INTERFACE_URL="http://127.0.0.1:12345/dolphinscheduler/datasources-ext/table-data/"+tableName;
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		//headers.add("token",dolphinschedulerToken);
		//headers.add("token","21f7eb3268631095a33552ac55a07496");

		HttpEntity<String> requestEntity = new HttpEntity<String>(requestBody.toJSONString(), headers);


		ResponseEntity<String> responseEntity = restTemplate.exchange(DATA_INTERFACE_URL, HttpMethod.POST, requestEntity, String.class);
		JSONObject ret = JSONObject.parseObject(responseEntity.getBody());
		if(ret==null){
			return R.fail("调用接口出错，请联系管理员");
		}
		dataShare.setCallCount(dataShare.getCallCount()+1);
		if(ret.containsKey("data")){
			JSONObject data=ret.getJSONObject("data");
			if(data!=null && data.containsKey("dataList")){
				dataShare.setCallRecords(dataShare.getCallRecords()+data.getJSONArray("dataList").size());
			}
		}

		dataShareService.updateById(dataShare);
		Integer code = ret.getInteger("code");
		String msg = ret.getString("msg");

		return R.data((code==0?200:code),ret.get("data"),msg);
	}
	
}
